#include "InterCode.h"

int temVarNo = 1;
int labelNo = 1;
int varNo = 1;

InterCode code_head = NULL;
InterCode code_tail = NULL;

void insertCode(InterCode p)
{
	assert(p != NULL);
	p->pre = NULL;
	p->next = NULL;
	if (code_head == NULL)
	{
		code_head = p;
		code_tail = p;
	}
	else
	{
		p->pre = code_tail;
		code_tail->next = p;
		code_tail = p;
	}
}

void deleteCode(InterCode p)
{
	assert(p != NULL);
	if (p == code_head)
	{
		code_head = p->next;
		code_head->pre = NULL;
	}
	else if (p == code_tail)
	{
		code_tail = p->pre;
		code_tail->next = NULL;
	}
	else
	{
		p->pre->next = p->next;
		p->next->pre = p->pre;
	}
	//may carefully free its oprands  e.g. operand label 两条语句中共用
	free(p);
}

void printOp(Operand p, FILE *fp)
{
	assert(fp != NULL);
	assert(p != NULL);
	char str[50];
	memset(str, 0, sizeof(str));
	switch (p->kind)
	{
	case TEMPVAR:
		sprintf(str, "t%d ", p->var_no);
		fputs(str, fp);
		break;
	case VARIABLE:
		assert(p->value != NULL);
		sprintf(str, "%s ", p->value);
		fputs(str, fp);
		break;
	case CONSTANT:
		sprintf(str, "#%s ", p->value);
		fputs(str, fp);
		break;
	case ADDRESS:
		fputs(p->value, fp);
		fputs(" ", fp);
		break;
	case LABEL:
		sprintf(str, "label%d ", p->var_no);
		fputs(str, fp);
		break;
	case FUNCTION_:
		sprintf(str, "%s ", p->value);
		fputs(str, fp);
		break;
	default:
		printf("Not expected operand, %x\n",p->kind);
		fputs("Not expected operand.", fp);
		return;
		assert(0);
	}
}

void printCode(char *fileName)
{
	FILE *fp = fopen(fileName, "w");
	if (fp == NULL)
	{
		perror(fileName);
		exit(-2);
	}
	for (InterCode p = code_head; p != NULL; p = p->next)
	{
		switch (p->kind)
		{
		case IR_ASSIGN:
			printOp(p->assign.left, fp);
			fputs(":= ", fp);
			printOp(p->assign.right, fp);
			break;
		case IR_ADD:
			printOp(p->binop.result, fp);
			fputs(":= ", fp);
			printOp(p->binop.op1, fp);
			fputs("+ ", fp);
			printOp(p->binop.op2, fp);
			break;
		case IR_SUB:
			printOp(p->binop.result, fp);
			fputs(":= ", fp);
			printOp(p->binop.op1, fp);
			fputs("- ", fp);
			printOp(p->binop.op2, fp);
			break;
		case IR_MUL:
			printOp(p->binop.result, fp);
			fputs(":= ", fp);
			printOp(p->binop.op1, fp);
			fputs("* ", fp);
			printOp(p->binop.op2, fp);
			break;
		case IR_DIV:
			printOp(p->binop.result, fp);
			fputs(":= ", fp);
			printOp(p->binop.op1, fp);
			fputs("/ ", fp);
			printOp(p->binop.op2, fp);
			break;
		case IR_RETURN:
			fputs("RETURN ", fp);
			printOp(p->sinop.op, fp);
			break;
		case IR_LABEL:
			fputs("LABEL ", fp);
			assert(0);
			printOp(p->sinop.op, fp);
			fputs(": ", fp);
			break;
		case IR_GOTO:
			fputs("GOTO ", fp);
			printOp(p->sinop.op, fp);
			break;
		case IR_IFGOTO:
			fputs("IF ", fp);
			printOp(p->triop.x, fp);

			fputs(p->triop.op, fp);
			fputs(" ", fp);
			printOp(p->triop.y, fp);

			fputs("GOTO ", fp);
			printOp(p->triop.label, fp);
			break;
		case IR_READ:
			fputs("READ ", fp);
			printOp(p->sinop.op, fp);
			break;
		case IR_WRITE:
			fputs("WRITE ", fp);
			printOp(p->sinop.op, fp);
			break;
		case IR_CALL:
			printOp(p->assign.left, fp);
			fputs(":= CALL ", fp);
			printOp(p->assign.right, fp);
			break;
		case IR_ARG:
			fputs("ARG ", fp);
			printOp(p->sinop.op, fp);
			break;
		case IR_FUNC:
			fputs("FUNCTION ", fp);
			printOp(p->sinop.op, fp);
			fputs(": ", fp);
			break;
		case IR_PARAM:
			fputs("PARAM ", fp);
			printOp(p->sinop.op, fp);
			break;
		case IR_DEC:
			fputs("DEC ", fp);
			printOp(p->dec.op, fp);
			char sizeStr[16];
			sprintf(sizeStr, "%d", p->dec.size);
			fputs(sizeStr, fp);
			//fputs(itoa(p->dec.size), fp);
			//linux 下只有 atoi 在stdlib.h头文件中  所以只能用以上方法替代
			break;
		case IR_DEREF_R:
			fputs("!! ", fp);
			printOp(p->assign.left, fp);
			fputs(":= *", fp);
			printOp(p->assign.right, fp);
			break;
		case IR_DEREF_L:
			fputs("!! *", fp);
			printOp(p->assign.left, fp);
			fputs(":= ", fp);
			printOp(p->assign.right, fp);
			break;
		case IR_ADDR:
			printOp(p->assign.left, fp);
			fputs(":= &", fp);
			printOp(p->assign.right, fp);
			break;
		default:

			assert(0);
		}
		fputs("\n", fp);
	}
	fclose(fp);
}

void optimizeGoto()
{	
	for (InterCode c = code_head; c != NULL; c = c->next)
	{
		//间隔一个的ifgoto
		if (c->kind == IR_IFGOTO)
		{
			InterCode c1 = c;
			InterCode c2 = c->next;
			if (c2 == NULL)
				break;
			InterCode c3 = c2->next;
			if (c3 == NULL)
				break;
			if (c2->kind == IR_GOTO && c3->kind == IR_LABEL && c1->triop.label == c3->sinop.op)
			{
				//inverse cond
				if (strcmp(c1->triop.op, "==") == 0)
					strcpy(c1->triop.op , "!=");				
				else if (strcmp(c1->triop.op, "!=") == 0)	
					strcpy(c1->triop.op , "==");			
				else if (strcmp(c1->triop.op, ">=") == 0)
					strcpy(c1->triop.op , "<");			
				else if (strcmp(c1->triop.op, "<") == 0)
					strcpy(c1->triop.op , ">=");			
				else if (strcmp(c1->triop.op, ">") == 0)
					strcpy(c1->triop.op , "<=");			
				else if (strcmp(c1->triop.op, "<=") == 0)
					strcpy(c1->triop.op , ">");			
				c1->triop.label = c2->sinop.op;
				deleteCode(c2);			
			}
		}
		else if (c->kind == IR_GOTO)
		{			
			InterCode c1 = c;
			//return 后不需要goto
			InterCode c0 = c->pre;
			assert(c0);
			if(c0->kind==IR_RETURN)
			{
				c=c0;
				deleteCode(c1);
				continue;
			}
			//下一条就是要goto指令
			InterCode c2 = c->next;
			if (c2 == NULL)
				break;
			if (c2->kind == IR_LABEL && c1->sinop.op == c2->sinop.op)
			{
				c=c->next;
				deleteCode(c1);
			}
		}
	}
}

//删除用不到的Label
void deleteLabel()
{
	for (InterCode c = code_head; c; c = c->next)
	{
		if (c->kind == IR_GOTO)
			c->sinop.op->valid=TRUE;		
		else if (c->kind == IR_IFGOTO)
			c->triop.label->valid=TRUE;
	}

	for (InterCode c = code_head; c; c = c->next)
	{
		if (c->kind == IR_LABEL && c->sinop.op->valid == FALSE)
		{
			InterCode c1 = c;
			c = c->pre;
			deleteCode(c1);
		}
	}
}

//省去了重复的常量计算在循环中计算很多次   比如可优化 x=-3 这种由minus引起的
void computeConst()
{
	for (InterCode p = code_head; p != NULL; p = p->next)
	{
		if (p->kind == IR_ADD || p->kind == IR_SUB || p->kind == IR_MUL || p->kind == IR_DIV)
		{
			Operand op1 = p->binop.op1;
			Operand op2 = p->binop.op2;
			Operand result = p->binop.result;

			if (result->kind == TEMPVAR && op1->kind == CONSTANT && op2->kind == CONSTANT)
			{
				int o1 = atoi(op1->value);
				int o2 = atoi(op2->value);
				int r = 0;
				switch (p->kind)
				{
				case IR_ADD:
					r = o1 + o2;
					break;
				case IR_SUB:
					r = o1 - o2;
					break;
				case IR_MUL:
					r = o1 * o2;
					break;
				case IR_DIV:
					r = o1 / o2;
					break;
				default:
					break;
				}
				//感觉直接把一个tempVar改成Const比较危险  意味着这个临时变量作为左值只能出现一次  目前一个tn确是只用一次没有问题
				printf("Attention: constant substitution applied\nReplace ");
				printOp(result,stdout);

				result->kind = CONSTANT;
				result->value = malloc(32);
				sprintf(result->value, "%d", r);

				printf(" by ");
				printOp(result,stdout);
				printf("\n");

				InterCode tmp = p;
				p = p->pre;
				deleteCode(tmp);
			}
		}
	}
}

//复制传播和死代码消除(i.e. t1=x ) 会比较复杂 后面有需要再做了  
//重复的label且都有用 出现的还是很少的
